/*
 *  Copyright (c) 2017 Lesly-Ann Daniel
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package nl.cypherpunk.statefuzzer.openvpn;

import net.automatalib.words.Alphabet;
import net.automatalib.words.impl.Alphabets;
import nl.cypherpunk.statefuzzer.fuzzing.SUT;

import java.io.File;
import java.net.SocketException;
import java.util.Arrays;


public class VPNSUL implements SUT<String, String> {
	Alphabet<String> alphabet;
	VPNTestService vpn;
	
	public VPNSUL(VPNConfig config) throws Exception {
		alphabet = Alphabets.fromList(Arrays.asList(config.alphabet.split(" ")));
		
		if(config.proto.equals("tcp")) {
			vpn = new VPNTestServiceTCP();
		} else {
			vpn = new VPNTestServiceUDP();
		}
		vpn.setTarget(config.target);
		vpn.setLocal(config.local);
		vpn.setRemote(config.remote);
		vpn.setLocalPort(config.localPort);
		vpn.setRemotePort(config.remotePort);
		vpn.setOutputDir(config.output_dir);
		File outputDir = new File(vpn.outputDir + File.separator +"Seed");
		outputDir.mkdirs();
		vpn.setAuth(config.auth);
		vpn.setCipher(config.cipher);
		if(config.cmd.equals("")) {
			vpn.setCommand(config.version, config.proto, config.method);
		} else {
			vpn.setCommand(config.cmd);
		}
		
		try {
			vpn.start();
		} catch(SocketException e) {
			e.printStackTrace();
			vpn.closeSocket();
			vpn.close();
		}
	}

	public String SendFuzzingMessage(byte[] message) throws Exception
	{
		return vpn.sendFuzzingMessage(message);
	}

	public int getCoverage(){
	    int coverage = 0;
	    try{
	        coverage = vpn.getCoverage();
        }
	    catch (Exception e)
        {
            return 0;
        }
	    return coverage;
	}

	public void exit(){
		try{
			vpn.closeSocket();
			//vpn.close();
		}
		catch (Exception e)
		{}
	}

	public Alphabet<String> getAlphabet() {
		return alphabet;
	}	

	public boolean canFork() {
		return false;
	}

	public byte[] getCurrent(){
		return vpn.currentCase.get(vpn.currentCase.size()-1);
	}

	@Override
	public String messageToSymbol(byte[] message){
		String[] tmp = message.toString().split(" ");
		return tmp[0];
	}

	@Override
	public String step(String symbol) {
		String result = null;
		try {
			result = vpn.processSymbol(symbol);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	@Override
	public void pre() {
		try {
			vpn.reset();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

	@Override
	public void post() {
		try {
			vpn.closeSocket();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}
}
